#ifndef GAME_H
#define GAME_H
#include <string>
#include <iostream>
#include <vector>
#include "Piece.h"

namespace DifficultyLevel
{
    /** \enum Difficulty Level
    *	\brief A Difficulty Level enum.
    *	\details An enum for the Difficulty Level.
    */
    enum Enum
    {
        Random,
        Easy,
        Medium,
        Hard
    };
}

extern DifficultyLevel::Enum difficulty;

/** \struct MOVE
*	\brief A MOVE struct
*	\details A struct that encapsulates a move. A MOVE contains 4 ints; fromX, fromY, toX, toY.
*/
struct MOVE {
	int fromX;
	int fromY;
	int toX;
	int toY;

	MOVE() { }

    /** \brief MOVE constructor
    *
    * Constructs a move with 4 integers.
    * @param[in] fx,fy Source coordinate
    * @param[in] tx,ty Destination coordinate
    */
	MOVE(int fx, int fy, int tx, int ty)
		:fromX(fx), fromY(fy), toX(tx), toY(ty)
	{
	}

    /** \brief MOVE comparison operator
    *
    * Compares two MOVEs.
    * @param[in] rhs Right-hand side MOVE.
    * \returns True if all 4 integers are same, else false.
    */
	bool operator==(const MOVE& rhs)
	{
	    return (fromX == rhs.fromX && fromY == rhs.fromY
             && toX == rhs.toX && toY == rhs.toY);
	}

	/** \brief MOVE assignment operator
    *
    * Assigns a MOVE.
    * @param[in] move The MOVE to assign.
    */
	void operator= (const MOVE &move)
	{
		fromX = move.fromX;
		fromY = move.fromY;
		toX = move.toX;
		toY = move.toY;
	}
	void print()
	{
		std::cout << fromX << "," << fromY << " to " << toX << "," << toY << "\n";
	}

};

typedef std::vector<Piece*> PieceVector;
typedef std::vector<PieceVector> GameBoard;

/** \class Game
*	\brief A Game class
*	\details An abstract Game class that defines a board game
*/
class Game
{
    public:
        /** \brief Game constructor
        *
        * Constructs a game.
        */
        Game();

        virtual ~Game();

        /** \brief Set Board
        *
        * Pure virtual function. Sets the board for the game.
        */
        virtual void setBoard() = 0;

        /** \brief Start game
        *
        * Pure virtual function. Starts the game.
        */
        virtual void start() = 0;

        /** \brief Init game
        *
        * Initializes the basic variables of the game.
        * Sets the board, currentPlayer, moveCount, piece count, adds the initial state and sets debugging to off.
        */
        virtual void init();

        /** \brief Display Board
        *
        * Displays the board, piece count and current player.
        */
        virtual void displayBoard();

        /** \brief Move Piece
        *
        * Pure virtual function. Moves the piece from (fromX,fromY) to (toX,toY)
        *
        * @param[in] fromX,fromY The source coordinate.
        * @param[in] toX,toY The destination coordinate.
        */
        virtual void movePiece(int fromX, int fromY, int toX, int toY) = 0;

		/** \brief Get legal moves
        *
        * Returns vector of legal MOVEs
        * \return Vector of MOVEs
        */
		std::vector<MOVE> legal();

        /** \brief Get legal moves
        *
        * A pure virtual function. Returns vector of legal MOVEs for the given state.
        * @param[in] state The state to find legal moves for.
        * \return Vector of MOVEs
        */
		virtual std::vector<MOVE> legal(GameBoard state) = 0;

        /** \brief Is Terminal
        *
        * Returns true if current state is a terminal state.
        * \returns True if terminal state, else false.
        */
		bool isTerminal();

        /** \brief Retract
        *
        * Retracts the last move by erasing last board object from the state history.
        */
        void retract();

        /** \brief Evaluate
        *
        * The evaluation value of the current board state using current difficulty level.
        * \returns The evaluation value.
        */
        int evaluate();

        /** \brief Toggle Debug
        *
        * Toggles debug mode on or off.
        */
        void toggleDebug();

        /** \brief Get Game Name
        *
        * Gets the game name.
        * \returns The game name.
        */
        std::string getGameName() const;

        /** \brief Get Current Player
        *
        * Gets the current player.
        * \returns The current player as 0 or 1.
        */
        int getCurrentPlayer() const;

        /** \brief Check for winner
        *
        * Checks if the game has a winner. Starts a new game if game is over.
        */
		void checkForWinner();

        /** \brief Winning state
        *
        * Checks if the game is a tie.
        * \returns 2 if the game is a tie, else -1.
        */
		virtual int winningState();

		virtual int advancedEvaluate() = 0;

    protected:
        /** \brief Set Current Player
        *
        * Sets the current player.
        * @param[in] player The current player.
        */
        void setCurrentPlayer(int player);

        /** \brief Count Pieces
        *
        * Counts the pieces of both players. Changes numPiecesP1 and numPiecesP2 accordingly.
        */
        void countPieces();

		GameBoard m_board; ///< The board as a vector of vectors of Pieces
		std::vector< GameBoard > m_stateHistory; ///< The state history as a vector of boards
		bool m_debug; ///< Debug mode on/off
		int m_currentPlayer; ///< The current player
		std::string m_name; ///< Game name
		int numPiecesP1; ///< Player 1 piece count
		int numPiecesP2; ///< Player 2 piece count
		int m_moveCount; ///< Total move count
    private:

};

#endif // GAME_H
